﻿using Autofac;
using Autofac.Extensions.DependencyInjection;
using DongFangGuoKai.WMS.NodeBussiness;
using DongFangGuoKai.WMS.NodeBussiness.FillEmptyBoxNode;
using DongFangGuoKai.WMSPlatform.Commn.HttpModule;
using DongFangGuoKai.WMSPlatform.Commn.TokenModule.Models;
using DongFangGuoKai.WMSPlatform.Core;
using DongFangGuoKai.WMSPlatform.Extensions;
using DongFangGuoKai.WMSPlatform.Service;
using DongFangGuoKai.WMSPlatform.WebApi.Extensions.SerilogExtend;
using DongFangGuoKai.WMSPlatform.WebApi.Job;
using DongFangGuoKai.WMSPlatform.WebApi.Job.JobDetails;
using DongFangGuoKai.WMSPlatform.WebApi.Utility;
using DongFangGuoKai.WMSPlatform.WebApi.Works;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration.Json;
using Microsoft.IdentityModel.Tokens;
using Quartz;
using Quartz.Impl;
using Quartz.Spi;
using RestSharp;
using Serilog;
using Serilog.Events;
using SqlSugar;
using System.Text;


namespace DongFangGuoKai.WMSPlatform.WebApi.Extensions
{
    public static class WebApplicationBuilderExtension
    {
        public static void ServiceEnter(this WebApplicationBuilder builder)
        {
            #region Serilog组件  配置文件+启动项配置   

            //加载Serilog配置文件
            var serilogConfig = new ConfigurationBuilder()
                 .SetBasePath(Directory.GetCurrentDirectory())
                 .Add(new JsonConfigurationSource { Path = @"serilogconfig.json", ReloadOnChange = true })
                 .Build();

            //数据库接收器配置对象
            var sinkOpts = new Serilog.Sinks.MSSqlServer.MSSqlServerSinkOptions();
            sinkOpts.TableName = "LogEvents";
            sinkOpts.AutoCreateSqlTable = true;

            //存储日志文件的路径
            string LogFilePath(string LogEvent) => $@"Logs/{LogEvent}/.log";
            //存储日志文件的格式
            string SerilogOutputTemplate = "{NewLine}" +
                "Date：{Timestamp:yyyy-MM-dd HH:mm:ss.fff}{NewLine}" +
                "LogLevel：{Level}{NewLine}" +
                "Controller:{SourceContext} {NewLine}" +
                "ThreadId:{ThreadId} {NewLine}" +
                "Message：{Message}{NewLine}{Exception}" + new string('-', 50);

            Serilog.Log.Logger = new Serilog.LoggerConfiguration()

                //排除Microsoft日志
                //.MinimumLevel.Override("Microsoft", Serilog.Events.LogEventLevel.Debug)
                //注册日志上下文 
                .Enrich
                //.FromLogContext()
                //自定义ILogEventEnricher 
                .With<ThreadIdEnricher>()
                .ReadFrom.Configuration(serilogConfig)
                //文件：分级别显示  
                //Debug
                .WriteTo.Logger(
                //Logger级别过滤器
                lg => lg.Filter.ByIncludingOnly(p => p.Level == LogEventLevel.Debug).WriteTo.File(LogFilePath("Debug"),
                                //每天生成一个
                                rollingInterval: RollingInterval.Day,
                                //输出模板
                                outputTemplate: SerilogOutputTemplate,
                                //启用最大字节数限制
                                rollOnFileSizeLimit: true,
                                //每个文件10M
                                fileSizeLimitBytes: 10_000_000,
                                //保存时间
                                retainedFileTimeLimit: TimeSpan.FromDays(30),
                                shared: true))
                //Infomation
                .WriteTo.Logger(
                 lg => lg.Filter.ByIncludingOnly(p => p.Level == LogEventLevel.Information).WriteTo.File(LogFilePath("Information"),
                                 rollingInterval: RollingInterval.Day,
                                 outputTemplate: SerilogOutputTemplate,
                                 rollOnFileSizeLimit: true,
                                 fileSizeLimitBytes: 10_000_000,
                                 retainedFileTimeLimit: TimeSpan.FromDays(30),
                                shared: true))
                //Warning
                .WriteTo.Logger(
                lg => lg.Filter.ByIncludingOnly(p => p.Level == LogEventLevel.Warning).WriteTo.File(LogFilePath("Warning"), rollingInterval: RollingInterval.Day,
                                outputTemplate: SerilogOutputTemplate,
                                rollOnFileSizeLimit: true,
                                fileSizeLimitBytes: 10_000_000,
                                retainedFileTimeLimit: TimeSpan.FromDays(30),
                                shared: true))
                //Error
                .WriteTo.Logger(
                lg => lg.Filter.ByIncludingOnly(p => p.Level == LogEventLevel.Error).WriteTo.File(LogFilePath("Error"),
                                rollingInterval: RollingInterval.Day,
                                outputTemplate: SerilogOutputTemplate,
                                rollOnFileSizeLimit: true,
                                fileSizeLimitBytes: 10_000_000,
                                retainedFileTimeLimit: TimeSpan.FromDays(30),
                                shared: true))
                //Fatal
                .WriteTo.Logger(
                lg => lg.Filter.ByIncludingOnly(p => p.Level == LogEventLevel.Fatal).WriteTo.File(LogFilePath("Fatal"),
                                rollingInterval: RollingInterval.Day,
                                outputTemplate: SerilogOutputTemplate,
                                rollOnFileSizeLimit: true,
                                fileSizeLimitBytes: 10_000_000,
                                retainedFileTimeLimit: TimeSpan.FromDays(30),
                                shared: true))
                //数据库存储：SqlServer
                // .WriteTo.MSSqlServer(
                // connectionString: builder.Configuration.GetConnectionString("Default"),
                // sinkOptions: sinkOpts
                //)
                .CreateLogger()  //清除内置日志框架
                ;
            builder.Host.UseSerilog(); // Register Serilog with the Host  
            #endregion

            //全局配置Json序列化处理
            builder.Services.AddControllers() //p=>p.Filters.Add(typeof(GlobalExceptionHandler))
            .AddNewtonsoftJson(opt =>
                {
                    //驼峰命名
                    opt.SerializerSettings.ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver();
                    //自定义小写
                    //opt.SerializerSettings.ContractResolver = new ToLowerPropertyNamesContractResolver();
                })
                .AddJsonOptions(options =>
            {
                // 不使用任何命名规则
                // options.JsonSerializerOptions.PropertyNamingPolicy = null;
            });

            builder.AddSwaggerExtend("DongFangGuoKai.WMSPlatform.WebApi.xml");

            builder.AddCorsExtend();
 
          
            #region SqlSugar
            //仓储
            builder.Services.AddScoped(typeof(Repository<>));

            //ORM
            builder.Services.AddTransient<ISqlSugarClient>(client =>
            {
                //创建数据库对象 (用法和EF Dappper一样通过new保证线程安全)
                SqlSugarClient Db = new SqlSugarClient(new ConnectionConfig()
                {
                    ConnectionString = builder.Configuration.GetConnectionString("STFZ"),
                    DbType = DbType.Oscar,
                    IsAutoCloseConnection = true
                }, db => {

                    db.Aop.OnLogExecuting = (sql, pars) =>
                    {

                        //获取原生SQL推荐 5.1.4.63  性能OK
                        Console.WriteLine(UtilMethods.GetNativeSql(sql, pars));

                        //获取无参数化SQL 对性能有影响，特别大的SQL参数多的，调试使用
                        //Console.WriteLine(UtilMethods.GetSqlString(DbType.SqlServer,sql,pars))


                    };

                    //注意多租户 有几个设置几个
                    //db.GetConnection(i).Aop

                }   );

                return Db;
            });
            #endregion

            #region RestHttpClient 
            builder.Services.AddTransient(provider =>
            {
                //请求设置
                RestClientOptions options = new RestClientOptions();
                //请求超时时间
                options.MaxTimeout = 60 * 1000;

                //Json序列化配置  默认驼峰
                {

                    //1、System.TextJson属性名称小写
                    //ConfigureSerialization serialConfig = s => s.UseSystemTextJson(new JsonSerializerOptions
                    //{
                    //    PropertyNamingPolicy = new LowerCaseNamingPolicy()
                    //});

                    //2、NewtonsoftJson属性名称小写设置

                    //驼峰命名
                    // ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver(),

                    //自定义小写方式命名
                    //ContractResolver = new ToLowerPropertyNamesContractResolver(),


                    //JsonSerializerSettings DefaultSettings = new JsonSerializerSettings
                    //{
                    //    ContractResolver = new ToLowerPropertyNamesContractResolver(),
                    //    DefaultValueHandling = DefaultValueHandling.Include,
                    //    TypeNameHandling = TypeNameHandling.None,
                    //    NullValueHandling = NullValueHandling.Ignore,
                    //    Formatting = Formatting.None,
                    //    ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor
                    //};                 

                    //ConfigureSerialization serialConfig = s => s.UseNewtonsoftJson(DefaultSettings);  

                }

                var client = new RestClient(
                options
                //configureSerialization: serialConfig
                );

                //默认请求头
                client.AddDefaultHeader("Content-Type", "application/json;charset=utf-8");

                return client;

            });
            builder.Services.AddSingleton<ICtmHttpClient, CtmHttpClient>();
            #endregion

            #region 后台任务
            builder.Services.AddHostedService(provider =>
            {

                Action<BackManagerOptions> action = option =>
                {
                    option.Name = "叫号机取样检索作业";
                    option.CheckTime = TimeSpan.FromSeconds(5);
                };


                CallNumberBackgroundService work = ActivatorUtilities.CreateInstance<CallNumberBackgroundService>(provider, action);

                return work;
            });

            //builder.Services.AddHostedService<QuartzHostedService>();
            #endregion

            #region Quartz 
            builder.Services.AddSingleton<IJobFactory, SingletonJobFactory>();
            builder.Services.AddSingleton<ISchedulerFactory, StdSchedulerFactory>();
            //定时补空箱任务
            builder.Services.AddSingleton<EmptyContanierToScrennAreaJob>();
            builder.Services.AddSingleton(new JobSchedule(jobType: typeof(EmptyContanierToScrennAreaJob), cronExpression: "0 */1 9-17 ? * MON-FRI")); // 周一到周五  9-17点 每一分钟执行  
            #endregion

            //批量注册
            builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
            builder.Host.ConfigureContainer<ContainerBuilder>(builder =>
            {
                builder.RegisterModule(new ApiModule());

            });
            builder.Services.AddAutoMapper(typeof(WMSPlatformProfile));

            #region Jwt验证   
            var token = builder.Configuration.GetSection("Jwt").Get<JwtTokenModel>();
            builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
            .AddJwtBearer(
                opt =>
                {
                    // 是否是Https，默认true
                    opt.RequireHttpsMetadata = false;
                    opt.SaveToken = true;
                    opt.TokenValidationParameters = new()
                    {
                        IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(token.Security)),
                        ValidIssuer = token.Issuer,
                        ValidAudience = token.Audience
                    };
                    opt.Events = new JwtBearerEvents
                    {
                        OnChallenge = context =>
                        {
                            //此处终止代码
                            context.HandleResponse();
                            var res = "{\"code\":401,\"err\":\"无权限\"}";
                            context.Response.ContentType = "application/json";
                            context.Response.StatusCode = StatusCodes.Status401Unauthorized;
                            context.Response.WriteAsync(res);
                            return Task.FromResult(0);
                        }
                    };
                }
            );
            #endregion

            #region 核心业务执行注入  
            builder.Services.AddSingleton<NodeBussinessFactory>();
            builder.Services.AddTransient<NodeBaseBusiness, PDACheckEmptyBox>();         
            #endregion

        }


    }
}
